package com.template.app.resolver;

import com.template.app.bean.DataTableRequest;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.util.Collections;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class DatatableMethodArgumentResolver implements HandlerMethodArgumentResolver {


    private static Pattern compile = Pattern.compile("([^\\]]*)\\[([^\\]]*)\\](\\[([^\\]]*)\\])?(\\[([^\\]]*)\\])?");

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().isAssignableFrom(DataTableRequest.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        DataTableRequest dataTableParameter = (DataTableRequest) parameter.getParameterType().newInstance();
        TreeMap<Integer, DataTableRequest.Column> columnTreeMap = new TreeMap<Integer, DataTableRequest.Column>(Collections.reverseOrder());
        TreeMap<Integer, DataTableRequest.Order> orderTreeMap = new TreeMap<Integer, DataTableRequest.Order>(Collections.reverseOrder());
        Iterator<String> parameterNames = webRequest.getParameterNames();

        while (parameterNames.hasNext()) {
            String name = parameterNames.next();
            String value = webRequest.getParameter(name);
            if ("draw".equals(name)) {
                dataTableParameter.setDraw(Integer.parseInt(value));
            } else if ("start".equals(name)) {
                dataTableParameter.setStart(Integer.parseInt(value));
            } else if ("length".equals(name)) {
                dataTableParameter.setLength(Integer.parseInt(value));
            } else {
                Matcher matcher = compile.matcher(name);
                if (matcher.matches()) {
                    String p1 = matcher.group(1);
                    String p2 = matcher.group(2);
                    String p4 = matcher.group(4);
                    String p6 = matcher.group(6);
                    if ("columns".equals(p1)) {
                        int index = Integer.parseInt(p2);
                        DataTableRequest.Column column = columnTreeMap.get(index);
                        if (column == null) {
                            column = new DataTableRequest.Column();
                            columnTreeMap.put(index, column);
                        }
                        if ("data".equals(p4)) {
                            column.setData(value);
                        } else if ("name".equals(p4)) {
                            column.setName(value);
                        } else if ("orderable".equals(p4)) {
                            column.setOrderable(Boolean.parseBoolean(value));
                        } else if ("searchable".equals(p4)) {
                            column.setSearchable(Boolean.parseBoolean(value));
                        } else if ("search".equals(p4)) {
                            if (column.getSearch() == null) {
                                column.setSearch(new DataTableRequest.Search());
                            }
                            if ("regex".equals(p6)) {
                                column.getSearch().setRegex(value);
                            } else if ("value".equals(p6)) {
                                column.getSearch().setValue(value);
                            }
                        }
                    } else if ("order".equals(p1)) {
                        int index = Integer.parseInt(p2);
                        DataTableRequest.Order order = orderTreeMap.get(index);
                        if (order == null) {
                            order = new DataTableRequest.Order();
                            orderTreeMap.put(index, order);
                        }
                        if ("dir".equals(p4)) {
                            order.setDir(value);
                        } else if ("column".equals(p4)) {
                            order.setColumn(Integer.parseInt(value));
                        }
                    } else if ("search".equals(p1)) {
                        if (dataTableParameter.getSearch() == null) {
                            dataTableParameter.setSearch(new DataTableRequest.Search());
                        }
                        if ("regex".equals(p2)) {
                            dataTableParameter.getSearch().setRegex(value);
                        } else if ("value".equals(p2)) {
                            dataTableParameter.getSearch().setValue(value);
                        }
                    }

                }
            }
        }
        int columns = columnTreeMap.size() > 0 ? columnTreeMap.keySet().iterator().next() + 1 : 0;
        dataTableParameter.setColumns(new DataTableRequest.Column[columns]);
        for (int i = 0; i < columns; i++) {
            dataTableParameter.getColumns()[i] = columnTreeMap.get(i);
        }

        int orders = orderTreeMap.size() > 0 ? orderTreeMap.keySet().iterator().next() + 1 : 0;
        dataTableParameter.setOrder(new DataTableRequest.Order[orders]);
        for (int i = 0; i < orders; i++) {
            dataTableParameter.getOrder()[i] = orderTreeMap.get(i);
        }
        return dataTableParameter;
    }
}
